<template>
  <div :class="prefixCls">
    <div class="design-wrap">
      <div class="flex-row">
        <div class="left-side">
          <a-tabs class="average-tabs" v-model:activeKey="activeKey" :tabBarGutter="10">
            <a-tab-pane key="1" tab="单元属性" />
            <a-tab-pane key="2" tab="数据源" />
          </a-tabs>
          <div class="tabs-content">
            <div v-show="activeKey === '1'">
              <ReportProperties v-bind="getPropertiesBind" v-if="!!state.activeData" />
            </div>
            <div class="dataSet-content" v-show="activeKey === '2'">
              <div class="dataSet-content-header">
                <a-button type="primary" size="small" preIcon="icon-ym icon-ym-btn-add" @click="handleAddDataSet">数据集</a-button>
                <a-button type="link" size="small" @click="handleConvertConfig" class="!p-0">数据转换</a-button>
              </div>
              <div class="dataSet-content-main" style="height: calc(100% - 102px)">
                <BasicLeftTree
                  ref="dataSetTreeRef"
                  :showSearch="false"
                  :treeData="dataSetList"
                  :fieldNames="{ key: 'jnpfId', title: 'fullName' }"
                  :actionList="actionList" />
              </div>
              <div class="set-query-wrap">
                <a-button type="primary" block @click="handleOpenQueryModal">查询配置</a-button>
              </div>
            </div>
          </div>
        </div>
        <div class="center-side" @click="clickDesignModule">
          <JnpfUniver
            ref="jnpfUniverRef"
            @focus-echart="handleFocusEchart"
            @change-cell-from-selection="handleChangeCellFromSelection"
            @preview="handlePreview" />
        </div>
      </div>
    </div>
  </div>
  <DataSetModal @register="registerDataSetModal" @confirm="onDataSetConfirm" />
  <ConvertModal @register="registerConvertModal" @confirm="updateConvertConfig" />
  <QueryModal @register="registerQueryModal" @confirm="onQueryConfirm" />
  <ReportPreview @register="registerPreview" />
</template>

<script lang="ts" setup>
  import { getPreviewDesign, uploadFileExcel } from '@/api/onlineDev/report';
  import { ref, reactive, toRefs, h, provide, onMounted, computed, watch, unref } from 'vue';
  import { BasicLeftTree, TreeActionItem } from '@/components/Tree';
  import { useMessage } from '@/hooks/web/useMessage';
  import { useI18n } from '@/hooks/web/useI18n';
  import { useModal } from '@/components/Modal';
  import { useDesign } from '@/hooks/web/useDesign';
  import { DataSetModal } from '@/components/CommonModal';
  import { FormOutlined, DeleteOutlined } from '@ant-design/icons-vue';
  import { cloneDeep, omit } from 'lodash-es';
  import { useDebounceFn } from '@vueuse/core';
  import ConvertModal from '@/components/PrintDesign/PrintDesign/ConvertModal.vue';
  import QueryModal from '../components/QueryModal.vue';
  import ReportProperties from '../properties/index.vue';
  import { defaultCellProperties } from '../helper';
  import { JnpfUniver } from '../jnpfUniver/index';
  import ReportPreview from '../reportPreview/index.vue';

  const props = defineProps({
    dataSetList: { type: Array, default: () => [] },
    convertConfig: { type: Array, default: () => [] },
    versionState: { type: Number, default: 0 },
    customs: { type: String as PropType<string | undefined>, default: undefined },
    snapshot: { type: String as PropType<string | undefined>, default: undefined },
    echarts: { type: String as PropType<string | undefined>, default: undefined },
    queryList: { type: String as PropType<string | undefined>, default: undefined },
    cells: { type: String as PropType<string | undefined>, default: undefined },
    versionId: { type: String as PropType<string | undefined>, default: undefined },
  });

  defineOptions({ name: 'reportDesign' });
  const emit = defineEmits(['closeVersionPopover', 'changeModalLoading']);
  const jnpfUniverRef = ref();

  provide('getDataSetList', () => state.dataSetList);

  interface State {
    activeKey: string;
    dataSetList: any[];
    convertConfig: any[];
    selectionsInfo: any[];
    firstCellConfig: object;
    queryList: any[];
    activeData: any;
    jnpfUniverAPI: any;
    isInitCell: boolean;
  }

  /**
   * 变量集合
   */
  const dataSetTreeRef = ref();
  const state = reactive<State>({
    activeKey: '1',
    dataSetList: [],
    convertConfig: [],
    selectionsInfo: [],
    firstCellConfig: {},
    queryList: [],
    activeData: null,
    jnpfUniverAPI: null,
    isInitCell: true,
  });
  const { activeKey, dataSetList } = toRefs(state);

  const { prefixCls } = useDesign('report-designer');
  const { createConfirm } = useMessage();
  const { t } = useI18n();
  const [registerDataSetModal, { openModal: openDataSetModal }] = useModal();
  const [registerConvertModal, { openModal: openConvertModal }] = useModal();
  const [registerQueryModal, { openModal: openQueryModal }] = useModal();
  const [registerPreview, { openModal: openPreviewModal }] = useModal();
  const debounceUpdateCellProperties = useDebounceFn(updateCellProperties, 200);

  const actionList: TreeActionItem[] = [
    {
      render: node => {
        if (!node.children) return null;
        return h(FormOutlined, {
          class: 'mr-4px',
          title: '编辑',
          onClick: e => {
            e.stopPropagation();
            handleEditDataSet(node);
          },
        });
      },
    },
    {
      render: node => {
        if (!node.children) return null;
        return h(DeleteOutlined, {
          class: 'mr-4px',
          title: '删除',
          onClick: e => {
            e.stopPropagation();
            handleDeleteDataSet(node);
          },
        });
      },
    },
  ];

  const getDefaultEchartOptions = computed(() => unref(jnpfUniverRef)?.getDefaultEchartOptions() ?? {});
  const getPropertiesBind = computed(() => ({
    activeData: state.activeData,
    dataSetList: state.dataSetList,
    defaultEchartOptions: unref(getDefaultEchartOptions),
    jnpfUniverRef,
  }));

  watch(
    () => state.activeData,
    () => {
      // 更新属性
      debounceUpdateCellProperties();
    },
    { deep: true },
  );

  const handleEditDataSet = (node: any) => {
    const data: any = omit(node, ['fullName_title', 'children']);
    handleOpenDataSetModal(data);
  };
  const handleDeleteDataSet = (node: any) => {
    createConfirm({
      iconType: 'warning',
      title: t('common.tipTitle'),
      content: '确定要删除该数据集吗?',
      onOk: () => {
        state.dataSetList = state.dataSetList.filter(o => o.jnpfId !== node.jnpfId);
      },
    });
  };
  // 添加数据集
  function handleAddDataSet() {
    handleOpenDataSetModal();
  }
  // 数据转换配置
  function handleConvertConfig() {
    const fieldOptions = state.dataSetList.map(o => ({
      ...o,
      disabled: true,
      children: !o.children ? [] : o.children.map(c => ({ ...c, fullName: o.fullName + '.' + c.fullName, id: o.fullName + '.' + c.id })),
    }));
    openConvertModal(true, { list: state.convertConfig, fieldOptions });
  }
  function updateConvertConfig(data) {
    state.convertConfig = data;
  }
  function handleOpenDataSetModal(data = null) {
    openDataSetModal(true, { data, list: state.dataSetList });
  }
  function onDataSetConfirm(data: any) {
    state.dataSetList = data.map((o: any) => ({
      ...o,
      children: !o.children ? [] : o.children.map(c => ({ ...c, jnpfId: o.fullName + '.' + c.id, fullName: c.label ? `${c.id}（${c.label}）` : c.id })),
    }));
  }
  // 暴露数据
  const getData = async () => {
    return new Promise(async resolve => {
      await unref(jnpfUniverRef)?.setCellEditVisible();
      const { snapshot, echarts, customs } = unref(jnpfUniverRef)?.getDesignWorkbookData();
      const customCells = !customs?.length
        ? []
        : customs.map(o => ({ col: o.col, row: o.row, sheet: o.sheetId, type: o.cellData?.custom?.type, custom: o.cellData?.custom || {} }));

      const cells = { cells: customCells, echarts };
      const data = {
        dataSetList: state.dataSetList.map(o => omit(o, ['fullName_title', 'children'])),
        convertConfig: JSON.stringify(state.convertConfig),
        queryList: JSON.stringify(state.queryList),
        snapshot: snapshot ? JSON.stringify(snapshot) : null,
        cells: JSON.stringify(cells),
      };
      resolve(data);
    });
  };
  // 销毁示例
  const handleDisposeUnit = () => {
    unref(jnpfUniverRef)?.handleDisposeUnit();
  };
  // 获取sheet列表
  function getSheetList() {
    const sheets = state.jnpfUniverAPI?.getActiveWorkbook()?.getSheets();
    const sheetList = sheets.map(o => ({ id: o.getSheetId(), fullName: o.getSheetName() }));
    return sheetList;
  }
  function init() {
    state.dataSetList = (props.dataSetList as any[]).map(o => ({
      ...o,
      jnpfId: o.id,
      children: !o.children ? [] : o.children.map(c => ({ ...c, jnpfId: o.fullName + '.' + c.id, fullName: c.label ? `${c.id}（${c.label}）` : c.id })),
    }));
    state.convertConfig = props.convertConfig;
    state.queryList = props.queryList ? JSON.parse(props.queryList) : [];
    const customs = props.cells ? JSON.parse(props.cells) : {};
    const echarts = customs.echarts || {};
    const snapshot = props.snapshot ? JSON.parse(props.snapshot) : {};
    handleCreate(snapshot, echarts);
  }
  // 创建报表实例
  function handleCreate(snapshot, echarts?) {
    const res = unref(jnpfUniverRef)?.handleCreateDesignUnit({
      snapshot,
      echarts,
    });
    state.jnpfUniverAPI = res ? res?.jnpfUniverAPI : null;
    onReportCommandExecuted();
  }
  function onReportCommandExecuted() {
    state.jnpfUniverAPI?.onCommandExecuted((command: any) => {
      const { id: commandId } = command ?? {};
      // 单元格清除内容/清除全部
      if (commandId === 'sheet.command.clear-selection-all' || commandId === 'sheet.command.clear-selection-content') {
        state.activeData.type = 'text';
        updateCellProperties();
      }
      // 导入excel
      if (commandId === 'jnpf-sheets.operation.import-excel-file') importExcel();
    });
  }
  function importExcel() {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = '.xlsx,.xls,.csv';
    input.click();
    input.onchange = () => {
      const file = input.files?.[0];
      if (!file) return;
      const formData = new FormData();
      formData.append('file', file);
      uploadFileExcel(formData).then(res => {
        const snapshot = res.data.snapshot ? JSON.parse(res.data.snapshot) : null;
        handleCreate(snapshot);
      });
    };
  }

  function handleOpenQueryModal() {
    const sheetList = getSheetList();
    openQueryModal(true, { dataSetList: state.dataSetList, queryList: state.queryList, sheetList });
  }
  function onQueryConfirm(data: any) {
    state.queryList = data;
  }
  // 图表聚焦
  function handleFocusEchart(data: any) {
    const custom = { ...data.option, chartType: data.echartType };
    const activeData: any = {
      drawingId: data.drawingId,
      type: 'chart',
      custom,
    };
    onActive(activeData);
  }
  // 单元格选中
  function handleChangeCellFromSelection(data: any) {
    const activeData: any = { ...data, type: data.cellData?.custom?.type || 'text', custom: data.cellData.custom || {} };
    state.isInitCell = true;
    onActive(activeData);
  }
  // 点击单元格或者图表
  function onActive(data) {
    const { type = 'text', custom = {} } = data;
    state.activeData = data;
    state.activeData.type = type;
    state.activeData.text = cloneDeep(type === 'text' ? custom : defaultCellProperties.text);
    state.activeData.chart = cloneDeep(type === 'chart' ? custom : unref(getDefaultEchartOptions).bar);
    state.activeData.dataSource = cloneDeep(type === 'dataSource' ? custom : defaultCellProperties.dataSource);
  }
  // 更新单元格或者图表属性
  function updateCellProperties() {
    if (state.isInitCell) return (state.isInitCell = false);
    const data = state.activeData;
    if (['dataSource', 'text'].includes(data.type)) {
      const cell = {
        startColumn: data.startColumn,
        startRow: data.startRow,
        cellData: {
          ...data.cellData,
          ...(data.type === 'dataSource' ? { v: data[data.type].field } : {}),
          custom: { ...data[data.type], type: data.type },
        },
      };
      unref(jnpfUniverRef)?.updateCellsData([cell]);
      return;
    }
    if (data.type === 'chart') {
      const dataCopy = cloneDeep(data);
      const option = getRealChartOptions(dataCopy.chart);
      const item = {
        drawingId: dataCopy.drawingId,
        echartType: dataCopy.chart.chartType,
        option,
      };
      unref(jnpfUniverRef)?.updateEchartOption(item);
    }
  }
  // 完善图表的option
  function getRealChartOptions(option) {
    option.series = option.series.map(o => ({
      ...o,
      type: option.chartType,
      ...(option.chartType === 'line' ? { smooth: option.line?.smooth } : {}),
      ...(option.chartType === 'pie'
        ? {
            radius: '50%',
            center: [option.seriesCenter.seriesCenterLeft + '%', option.seriesCenter.seriesCenterTop + '%'],
            roseType: option.pie?.roseType,
            emphasis: {
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)',
              },
            },
          }
        : {}),
      ...(option.chartType === 'radar' ? { center: [option.seriesCenter.seriesCenterLeft + '%', option.seriesCenter.seriesCenterTop + '%'] } : {}),
    }));
    return option;
  }

  function clickDesignModule() {
    emit('closeVersionPopover');
  }
  function handlePreview() {
    emit('changeModalLoading', true);
    getPreviewDesign(props.versionId)
      .then(_ => {
        openPreviewModal(true, { id: '', versionId: props.versionId });
      })
      .finally(() => {
        return emit('changeModalLoading', false);
      });
  }

  onMounted(() => {
    init();
  });

  defineExpose({ getData, handleDisposeUnit });
</script>

<style lang="less">
  @import '../../style/index.less';

  .tabs-content {
    overflow-x: hidden;
    overflow-y: auto;
    .right-radio {
      .ant-radio-button-wrapper {
        padding: 0 11px;
      }
    }
  }

  .dataSet-content {
    overflow: hidden;
  }

  .set-query-wrap {
    border-top: 1px solid @border-color-base1;
    padding: 10px;
    box-sizing: border-box;
  }

  .univer-dialog-root .univer-dialog-mask {
    background: #00000080 !important;
  }
</style>
